﻿using MyCode.Project.Domain.Message.Response.EnterpriseWechat;
using MyCode.Project.Domain.Message.Response.Wechat;
using MyCode.Project.Infrastructure.Cache;
using MyCode.Project.Infrastructure.Common;
using MyCode.Project.Infrastructure.Constant;
using MyCode.Project.Infrastructure.Exceptions;
using MyCode.Project.Infrastructure.WebPost;
using Senparc.CO2NET.Extensions;
using Senparc.Weixin;
using Senparc.Weixin.MP.Entities;
using Senparc.Weixin.MP.Helpers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;

namespace MyCode.Project.OutSideService.Implementation
{
    public class EnterpriseWechatService  : IEnterpriseWechatService
    {
        private readonly string apiUrl = "https://qyapi.weixin.qq.com/";


        private readonly IMyCodeCacheService _myCodeCacheService;
     
        public EnterpriseWechatService(
            IMyCodeCacheService myCodeCacheService
           )
        {
            _myCodeCacheService = myCodeCacheService;
          
        }

        #region 基础辅助

        #region Get(进一步封装Get方法)
        /// <summary>
        /// 进一步封装Get方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <returns></returns>
        private T Get<T>(string url) where T : BaseEnterpriseResp
        {
            var webUtils = new WebUtils();

            var resp = webUtils.DoGet<T>(url, null);

            resp.CheckResult();

            return resp;
        }
        #endregion

        #region ToDepartmentHasChild(部门转成含有子节点的结构)
        public List<DepartmentHasChild> ToDepartmentHasChild(List<DepartmentInfo> listDepartmentInfo)
        {
            if (listDepartmentInfo == null || listDepartmentInfo.Count == 0) { return null; }

            //公司节点
            var rootList = listDepartmentInfo.FindAll(p => p.Parentid == 0);

            var returnList = new List<DepartmentHasChild>();

            //子节点
            foreach (var root in rootList)
            {
                var item = new DepartmentHasChild
                {
                    Id = root.Id,
                    Name = root.Name,
                    Parentid = root.Parentid
                };

                item.ListChild = GetDepartmentChild(listDepartmentInfo, root.Id);

                returnList.Add(item);
            }

            return returnList;
        }
        #endregion

        #region GetDepartmentChild(得到部门子节点)
        /// <summary>
        /// 得到子节点
        /// </summary>
        /// <param name="listDepartmentInfo"></param>
        /// <param name="parentId"></param>
        /// <returns></returns>
        public List<DepartmentHasChild> GetDepartmentChild(List<DepartmentInfo> listDepartmentInfo, int parentId)
        {
            var list = listDepartmentInfo.FindAll(p => p.Parentid == parentId);

            var returnList = new List<DepartmentHasChild>();

            if (list == null || list.Count == 0) { return new List<DepartmentHasChild> { }; }

            foreach (var child in list)
            {
                var item = new DepartmentHasChild
                {
                    Id = child.Id,
                    Name = child.Name,
                    Parentid = child.Parentid,
                    Order = child.Order
                };
                item.ListChild = GetDepartmentChild(listDepartmentInfo, child.Id);

                returnList.Add(item);

            }


            return returnList;
        }
        #endregion

        #endregion

        #region GetAccessToken(得到AccessToken，有效期7200秒)
        /// <summary>
        /// 得到AccessToken，有效期7200秒
        /// </summary>
        /// <param name="corpId">企业id</param>
        /// <param name="secret"></param>
        /// <returns></returns>
        public string GetAccessToken(string corpId, string secret)
        {
            var cacheKey = $"{CacheKey.EnterpriseWechatTokenKey}{corpId}{secret}";

            if (_myCodeCacheService.Exists(cacheKey))
            {
                return _myCodeCacheService.Get<string>(cacheKey);
            }
            var url = $"{apiUrl}cgi-bin/gettoken?corpid={corpId}&corpsecret={secret}";

            var resp = Get<GetTokenResp>(url);

            var token = resp.Access_token;

            _myCodeCacheService.Set(cacheKey, token, new TimeSpan(1, 0, 0));

            return token;
        }
        #endregion

        #region GetTicket(获取企业微信Ticket)
        /// <summary>
        /// 获取企业微信Ticket
        /// </summary>
        /// <param name="accessToken">对应的应用的token</param>
        /// <returns></returns>
        private string GetTicket(string accessToken)
        {
            var cacheKey = $"{accessToken}";

            if (_myCodeCacheService.Exists(cacheKey))
            {
                return _myCodeCacheService.Get<string>(cacheKey);
            }

            var url = string.Format(apiUrl + "cgi-bin/get_jsapi_ticket?access_token={0}", accessToken.AsUrlData());

            JsApiTicketResult result = Senparc.CO2NET.HttpUtility.Get.GetJson<JsApiTicketResult>(url);

            if (result.errcode != ReturnCode.请求成功) { throw new BaseException(result.ToJson()); }

            _myCodeCacheService.Set(cacheKey, result.ticket, new TimeSpan(1, 0, 0));


            return result.ticket;
        }
        #endregion

        #region GetApplicationTicket(应用的jsapi_ticket)
        /// <summary>
        /// 应用的jsapi_ticket
        /// </summary>
        /// <param name="accessToken">对应的应用的token</param>
        /// <returns></returns>
        private string GetApplicationTicket(string accessToken)
        {
            var cacheKey = $"{accessToken}2";

            if (_myCodeCacheService.Exists(cacheKey))
            {
                return _myCodeCacheService.Get<string>(cacheKey);
            }

            var url = string.Format(apiUrl + "cgi-bin/ticket/get?access_token={0}&type=agent_config", accessToken.AsUrlData());

            JsApiTicketResult result = Senparc.CO2NET.HttpUtility.Get.GetJson<JsApiTicketResult>(url);

            if (result.errcode != ReturnCode.请求成功) { throw new BaseException(result.ToJson()); }

            _myCodeCacheService.Set(cacheKey, result.ticket, new TimeSpan(1, 0, 0));


            return result.ticket;
        }
        #endregion

        #region GetJsSdk(取得企业微信JsSdk相关参数值)
        /// <summary>
        /// 取得微信JsSdk相关参数值
        /// </summary>
        /// <param name="appId">微信应用ID</param>
        /// <param name="ticket">JsTicket</param>
        /// <param name="url">需要授权Url地址</param>
        /// <returns></returns>
        private JsSdkResp GetJsSdk(string appId, string ticket, string url)
        {
            var decodeUrl = HttpUtility.UrlDecode(url);
            string timeStamp = JSSDKHelper.GetTimestamp();
            string nonceStr = JSSDKHelper.GetNoncestr();

            string signature = "";
            var paySignReqHandler = new Senparc.Weixin.TenPay.V2.RequestHandler(null);

            paySignReqHandler.SetParameter("jsapi_ticket", ticket);
            paySignReqHandler.SetParameter("noncestr", nonceStr);
            paySignReqHandler.SetParameter("timestamp", timeStamp);
            paySignReqHandler.SetParameter("url", decodeUrl);

            signature = paySignReqHandler.CreateSHA1Sign();

            return new JsSdkResp
            {
                AppId = appId,
                Timestamp = timeStamp,
                NonceStr = nonceStr,
                Signature = signature
            };
        }
        #endregion

        #region 获取企业微信的JS-SDK权限验证的签名Signature
        /// <summary>
        ///  获取企业微信的JS-SDK权限验证的签名Signature
        /// </summary>
        /// <param name="jsapi_ticket">jsapi_ticket</param>
        /// <param name="noncestr">随机字符串(必须与wx.config中的nonceStr相同)</param>
        /// <param name="timestamp">时间戳(必须与wx.config中的timestamp相同)</param>
        /// <param name="url">当前网页的URL，不包含#及其后面部分(必须是调用JS接口页面的完整URL)</param>
        /// <returns></returns>
        private string GetSignature(string jsapi_ticket, string noncestr, long timestamp, string url)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("jsapi_ticket=").Append(jsapi_ticket).Append("&")
             .Append("noncestr=").Append(noncestr).Append("&")
             .Append("timestamp=").Append(timestamp).Append("&")
             .Append("url=").Append(url.IndexOf("#") >= 0 ? url.Substring(0, url.IndexOf("#")) : url);
            string dddd = sb.ToString();
            LogHelper.Info("Signature:   " + dddd);
            return Senparc.CO2NET.Helpers.EncryptHelper.GetSha1(sb.ToString()).ToLower();
        }
        #endregion

        //#region GetJsSdk(取得企业微信某个应用的JsSdk相关参数值)
        ///// <summary>
        ///// 取得企业微信某个应用的JsSdk相关参数值
        ///// </summary>
        ///// <param name="url"></param>
        ///// <param name="tokenType">第一步传 1 第二步传2</param>
        ///// <returns></returns>
        //public EnterpriseWechatJsSdkResp GetJsSdk(string url, int tokenType = 1)
        //{

        //    EnterpriseWechatJsSdkResp result = new EnterpriseWechatJsSdkResp();
           


        //    string corpId = companyConfig.Corpid;
        //    string agentId = companyConfig.CustomerAgentidId.Replace("\r\n", "");
        //    string secret = companyConfig.CustomerDetailSecret;
        //    string ticket = "";

        //    string token = GetAccessToken(corpId, secret);
        //    long timeStamp = 0;
        //    string nonceStr = "";

        //    if (tokenType == 1)
        //    {
        //        ticket = GetTicket(token);
        //        timeStamp = long.Parse(JSSDKHelper.GetTimestamp());
        //        nonceStr = JSSDKHelper.GetNoncestr();
        //    }
        //    else if (tokenType == 2)
        //    {
        //        result = _myCodeCacheService.Get<EnterpriseWechatJsSdkResp>(companyConfig.Corpid + "1");
        //        ticket = GetApplicationTicket(token);
        //        timeStamp = long.Parse(result.Timestamp);
        //        nonceStr = result.NonceStr;
        //    }
        //    else
        //    {
        //        return null;
        //    }

        //    //var decodeUrl = HttpUtility.UrlDecode(url);

        //    string signature = GetSignature(ticket, nonceStr, timeStamp, url);
        //    result.CorpId = corpId;
        //    result.AgentId = agentId;
        //    result.NonceStr = nonceStr;
        //    result.Signature = signature;
        //    result.Timestamp = timeStamp.ToString();
        //    //LogHelper.Info("result:");
        //    //LogHelper.Info(result);
        //    _myCodeCacheService.Set(cacheKey, result, new TimeSpan(1, 0, 0));

        //    return result;

        //}
        //#endregion

        #region GetDepartmentList(得到部门列表)
        /// <summary>
        /// 取得通讯录的部门列表，使用通讯录Token
        /// </summary>
        /// <param name="accessToken">Token</param>
        /// <returns></returns>
        public List<DepartmentHasChild> GetDepartmentList(string accessToken, string corpId, string secret)
        {
            if (string.IsNullOrWhiteSpace(accessToken))
            {
                accessToken = GetAccessToken(corpId, secret);
            }
            var url = $"{apiUrl}cgi-bin/department/list?access_token={accessToken}";

            var resp = Get<DepartmentResp>(url);

            if (resp.Department == null || resp.Department.Count == 0) { return new List<DepartmentHasChild> { }; }

            return GetDepartmentChild(resp.Department, 0);
        }
        #endregion

        #region GetDepartmentMemberList(得到部门的员工列表)
        /// <summary>
        /// 得到部门的员工列表
        /// </summary>
        /// <param name="accessToken">通讯录的token</param>
        /// <param name="departmentId">部门id</param>
        /// <param name="fetch_child">是否递归获取子部门下面的成员：1-递归获取，0-只获取本部门</param>
        /// <returns></returns>
        public List<DepartmentMemberInfo> GetDepartmentMemberList(string accessToken, long departmentId, string corpId, string secret, int fetch_child = 0)
        {
            //if (departmentId == 0) { throw new BaseException("部门id不能为0"); }
            if (string.IsNullOrWhiteSpace(accessToken))
            {
                accessToken = GetAccessToken(corpId, secret);
            }
            var url = $"{apiUrl}cgi-bin/user/simplelist?access_token={accessToken}&department_id={departmentId}&fetch_child={fetch_child}";//是否递归获取子部门下面的成员：1-递归获取，0-只获取本部门

            var resp = Get<DepartmentMemberInfoResp>(url);

            if (resp.Userlist == null || resp.Userlist.Count == 0) { return new List<DepartmentMemberInfo> { }; }

            return resp.Userlist;
        }
        #endregion

        #region GetEmployeeInfo(获取员工信息)
        /// <summary>
        /// 获取员工信息
        /// </summary>
        /// <param name="userId">员工id</param>
        /// <returns></returns>
        public EnterpriseEmployeeInfo GetEmployeeInfo(string userId, string corpId, string secret)
        {
            if (string.IsNullOrWhiteSpace(userId)) { throw new BaseException("员工id不能为空"); }
            var accessToken = GetAccessToken(corpId, secret);
            var url = $"{apiUrl}/cgi-bin/user/get?access_token={accessToken}&userid={userId}";
            var webUtils = new WebUtils();
            var resp = webUtils.DoGet<EnterpriseEmployeeInfo>(url, null);
            return resp;
        }
        #endregion
        //#region GetLoginUserInfo(获取登录用户信息)
        ///// <summary>
        ///// 获取登录用户信息
        ///// </summary>
        ///// <param name="code"></param>
        ///// <param name="corpId"></param>
        ///// <param name="secret">自建应用secret</param>
        ///// <returns></returns>
        //public UserInfoResp GetLoginUserInfo(string code, string corpId = "", string secret = "")
        //{
        //    var accessToken = GetAccessToken(corpId, secret);
        //    var url = $"{apiUrl}/cgi-bin/user/getuserinfo?access_token={accessToken}&code={code}";
        //    var result = Get<UserInfoResp>(url);
        //    return result;
        //}
        //#endregion

        #region 从url读取内容到内存Stream流中
        /// <summary>
        /// 从url读取内容到内存Stream流中
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public Stream DownLoadFielToStream(string url)
        {
            var wreq = HttpWebRequest.Create(url) as HttpWebRequest;
            HttpWebResponse response = wreq.GetResponse() as HttpWebResponse;
            MemoryStream ms = null;
            using (var stream = response.GetResponseStream())
            {
                Byte[] buffer = new Byte[response.ContentLength];
                int offset = 0, actuallyRead = 0;
                do
                {
                    actuallyRead = stream.Read(buffer, offset, buffer.Length - offset);
                    offset += actuallyRead;
                }
                while (actuallyRead > 0);
                ms = new MemoryStream(buffer);
            }
            response.Close();
            return ms;
        }
        #endregion




        //#region openid转userid
        ///// <summary>
        ///// openid转userid
        ///// </summary>
        ///// <param name="openid"></param>
        ///// <param name="corpId"></param>
        ///// <param name="secret">通讯录secret</param>
        ///// <returns></returns>
        //public OpenIdChangeUseridResp GetUseridByOpenid(string openid, string corpId = "", string secret = "")
        //{
        //    var accessToken = GetAccessToken(corpId, secret);
        //    var url = $"{apiUrl}cgi-bin/user/convert_to_userid?access_token={accessToken}";
        //    var webUtils = new WebUtils();
        //    var resp = webUtils.DoGet<OpenIdChangeUseridResp>(url, null);
        //    return resp;
        //}
        //#endregion


        #region userid转openid
        /// <summary>
        /// userid转openid
        /// </summary>
        /// <param name="openid"></param>
        /// <param name="corpId"></param>
        /// <param name="secret">通讯录secret</param>
        /// <returns></returns>
        public UserIdChangeOpenIdResp GetOpenidByUserid(string userId, string corpId = "", string secret = "")
        {
            var accessToken = GetAccessToken(corpId, secret);
            var url = $"{apiUrl}cgi-bin/user/convert_to_openid?access_token={accessToken}";
            string json = $@"{{
   ""userid"": ""{userId}""
}}";
            var webUtils = new WebUtils();
            var resp = webUtils.DoPostJson(url, json);
            UserIdChangeOpenIdResp resut = JsonHelper.ToObject<UserIdChangeOpenIdResp>(resp);
            return resut;
        }
        #endregion

    }
}
